/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.paging;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import org.zhiqim.kernel.constants.CodeConstants;
import org.zhiqim.kernel.constants.SignConstants;
import org.zhiqim.kernel.model.maps.HashMapSS;
import org.zhiqim.kernel.model.maps.MapSS;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Urls;

/**
 * 分页结果类
 *
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class PageResult<E> implements SignConstants, CodeConstants
{
    //默认条件为UTF-8编码
    private String conditionEncoding = _UTF_8_;
    
    //以下六项由构造函数初始化
    private int total;                              //总记录数
    private int pageSize;                           //每页数
    private int pageNo;                             //当前页码
    private int totalPages;                         //总页数,由总记录数和每页数计算得出
    private List<E> records;                        //当前页记录实体
    private MapSS conditionMap;                    //返回的URL条件，如：https://www.zhiqim.com/list.do?menu=news&page=1中对应的key=menu,value=news
    
    //以下四项用于基本分页,为默认初始化
    private boolean hasFirst = false;               //是否需要首页
    private boolean hasPrevious = false;            //是否需要上一页
    private boolean hasNext = false;                //是否需要下一页
    private boolean hasLast = false;                //是否需要末页
    
    /** 包访问下构造方法 */
    PageResult(int total, int pageNo, int pageSize, List<E> records)
    {
        if (pageNo < 1) pageNo = 1;
        if (pageSize < 1) pageSize = 10;
        
        this.conditionMap = new HashMapSS(7);
        
        this.total = total;
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.totalPages = (total-1)/pageSize + 1;

        if (pageNo > 1)
        {
            this.hasFirst = true;
            this.hasPrevious = true;
        }
        if (pageNo < this.totalPages)
        {
            this.hasNext = true;
            this.hasLast = true;
        }
        
        if (records == null)
            this.records = new ArrayList<E>();
        else
            this.records = records;
    }
    
    PageResult(boolean hasNext, int pageNo, int pageSize, List<E> records)
    {
        if (pageNo < 1) pageNo = 1;
        if (pageSize < 1) pageSize = 10;
        
        this.conditionMap = new HashMapSS(7);
        
        this.total = -1;
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.totalPages = -1;
        this.hasFirst = false;
        this.hasLast = false;
        
        if (pageNo > 1)
        {
            this.hasPrevious = true;
        }
        this.hasNext = hasNext;
        
        if (records == null)
            this.records = new ArrayList<E>();
        else
            this.records = records;
    }
    
    @Override
    public String toString()
    {
        StringBuilder strb = new StringBuilder("PageResult:{");
        if (total == -1)
            strb.append("hasNext:").append(hasNext).append(",");
        else
        {
            strb.append("total:").append(total).append(",")
                .append("totalPage:").append(totalPages).append(",");
        }
        
        strb.append("pageNo:").append(pageNo).append(",")
            .append("pageSize:").append(pageSize).append(",")
            .append("size:").append(size()).append(",").append(_BR_)
            .append("[").append(_BR_);
        
        for (int i=0;i<records.size();i++)
        {
            strb.append(records.get(i)).append(_BR_);
        }
        
        return strb.append("]").append(_BR_).append("}").toString();
    }
    
    /************************************************/
    //分页基本属性设置，包括条件设置，可选的分页段设置
    /************************************************/
    
    /** 获取条件编码 */
    public String getConditionEncoding()
    {
        return conditionEncoding;
    }

    /** 设置条件编码 */
    public void setConditionEncoding(String coditionEncoding)
    {
        this.conditionEncoding = coditionEncoding;
    }
    
    /** 获取条件列表 */
    public MapSS getConditionMap()
    {
        return conditionMap;
    }
    
    /** 提供增加单条条件 */
    public void addCondition(String key, String value)
    {
        if ("page".equalsIgnoreCase(key) || "pageNo".equalsIgnoreCase(key) || value == null)
            return;
        
        conditionMap.put(key, Strings.trim(value));
    }

    /** 提供增加条件列表 */
    public void addConditionMap(MapSS condMap)
    {
        for (Entry<String, String> entry : condMap.entrySet())
        {
            if ("page".equalsIgnoreCase(entry.getKey()) || "pageNo".equalsIgnoreCase(entry.getKey()) || entry.getValue() == null)
                continue;//分页编号本身不要放在表中
            
            conditionMap.put(entry.getKey(), Strings.trim(entry.getValue()));
        }
    }
    
    /** 获取条件组成的URL */
    public String getConditionUrl()
    {
        if (conditionMap.isEmpty())
            return _EMPTY_;

        StringBuilder strb = new StringBuilder("?");
        for (Entry<String, String> entry : conditionMap.entrySet())
        {
            String key = entry.getKey();
            String value = Urls.encode(entry.getValue(), conditionEncoding);
            
            strb.append(key).append("=").append(value).append("&");
        }
        strb.setLength(strb.length()-1);
        return strb.toString();
    }
    
    /***************************************************/
    //分页信息，总数、列表、列表记录数，页数，页码、页大小
    /***************************************************/
    
    /** 获取总记录数 */
    public int total()
    {
        return total;
    }
    
    /** 获取记录列表*/
    public List<E> list()
    {
        return records;
    }
    
    /** 获取记录条数 */
    public int size()
    {
        return records.size();
    }
    
    /** 是否有记录 */
    public boolean isEmpty()
    {
        return records.isEmpty();
    }
    
    /** 获取总页数 */
    public int totalPages()
    {
        return totalPages;
    }

    /** 获取当前页 */
    public int pageNo()
    {
        return pageNo;
    }

    /** 获取每页记录数 */
    public int pageSize()
    {
        return pageSize;
    }
    
    /********************************************/
    //分页判断信息，上下页、首末页、左右边界
    /********************************************/
    
    /** 检查是否需要首页 */
    public boolean hasFirst()
    {
        return hasFirst;
    }

    /** 检查是否需要上一页 */
    public boolean hasPrevious()
    {
        return hasPrevious;
    }

    /** 检查是否需要下一页 */
    public boolean hasNext()
    {
        return hasNext;
    }

    /** 检查是否需要末页 */
    public boolean hasLast()
    {
        return hasLast;
    }
    
    /** 检查左边界是否需要 */
    public boolean hasLSegment(int segmentSize)
    {
        return (pageNo-1)/segmentSize > 0;
    }
    
    /** 检查右边界是否需要 */
    public boolean hasRSegment(int segmentSize)
    {
        return (pageNo-1)/segmentSize < (totalPages-1)/segmentSize;
    }
    
    /** 获取左边界值 */
    public int getLSegmentNo(int segmentSize)
    {
        return ((pageNo-1)/segmentSize) * segmentSize + 1;
    }
    
    /** 获取右边界值 */
    public int getRSegmentNo(int segmentSize)
    {
        int rSegmentNo = ((pageNo-1)/segmentSize + 1) * segmentSize + 1;
        return rSegmentNo>totalPages?(totalPages+1):rSegmentNo;
    }
}
